/*
 * (C) Copyright 2013
 * David Feng <fenghua@phytium.com.cn>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <common.h>
#include <command.h>

static int get_data_size(char* arg, int default_size)
{
	/* Check for a size specification .b, .w or .l.
	 */
	int len = strlen(arg);
	if (len > 2 && arg[len-2] == '.') {
		switch(arg[len-1]) {
		case 'b':
			return 1;
		case 'w':
			return 2;
		case 'l':
			return 4;
		case 'q':
			return 8;
		case 's':
			return -2;
		default:
			return -1;
		}
	}
	return default_size;
}

static int do_io_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	ulong	addr, readvalue;
	int	size, count;

	if ((argc < 2) || (argc > 3))
		return CMD_RET_USAGE;

	/* Check for size specification.
	*/
	if ((size = get_data_size(argv[0], 8)) < 1)
		return 1;

	/* Address is specified since argc > 1
	*/
	addr = simple_strtoul(argv[1], NULL, 16);

	/* Count ? */
	if (argc == 3) {
		count = simple_strtoul(argv[2], NULL, 16);
	} else {
		count = 1;
	}

	while (count-- > 0) {
		if (size == 8) {
			readvalue = *((u64 *)addr);
			printf("%lx: %016lx\n", addr, readvalue);
		} else if (size == 4) {
			readvalue = *((u32 *)addr);
			printf("%lx: %08lx\n", addr, readvalue);
		} else if (size == 2) {
			readvalue = *((u16 *)addr);
			printf("%lx: %04lx\n", addr, readvalue);
		} else {
			readvalue = *((u8 *)addr);
			printf("%lx: %02lx\n", addr, readvalue);
		}

		addr += size;
	}

	return 0;
}

static int do_io_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	ulong	addr, writeval;
	int	size;

	if (argc != 3)
		return CMD_RET_USAGE;

	/* Check for size specification.
	*/
	if ((size = get_data_size(argv[0], 8)) < 1)
		return 1;

	/* Address is specified since argc > 1
	*/
	addr = simple_strtoul(argv[1], NULL, 16);

	/* Get the value to write.
	*/
	writeval = simple_strtoul(argv[2], NULL, 16);

	if (size == 8)
		*((u64 *)addr) = (u64)writeval;
	else if (size == 4)
		*((u32 *)addr) = (u32)writeval;
	else if (size == 2)
		*((u16 *)addr) = (u16)writeval;
	else
		*((u8 *)addr) = (u8)writeval;

	return 0;
}

/**************************************************/
U_BOOT_CMD(
	ior,	3,	1,	do_io_read,
	"memory mapped io region read",
	"[.b, .w, .l, .q] address [count]"
);

U_BOOT_CMD(
	iow,	3,	1,	do_io_write,
	"memory mapped io region write",
	"[.b, .w, .l, .q] address value"
);
